﻿
namespace TinyMceWrapper.Web.UI.WebControls
{

    #region [ Imports ]

    using System;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics.CodeAnalysis;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Globalization;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using TinyMceWrapper.Web.UI.Design;

    #endregion

    /// <summary>
    /// TinyMce WYSIWYG editor server control.
    /// </summary>
    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Mce"), ToolboxData("<{0}:TinyMce runat=\"server\" />")]
    [DefaultProperty("Text"), DefaultEvent("TextChanged"), Designer(typeof(EmptyDesigner)), ValidationProperty("Text"), ControlBuilder(typeof(TinyMceControlBuilder))]
    [ParseChildren(true, "Text"), ToolboxBitmap(typeof(TinyMce))]
    public class TinyMce : WebControl, IPostBackDataHandler, IEditableTextControl, ITextControl
    {

        #region [ Local Fields ]

        private static readonly object _textChangedEvent = new object();

        #endregion

        #region [ Constructors ]

        /// <summary>
        /// Initializes a new instance of TinyMce class.
        /// </summary>
        public TinyMce() : base(HtmlTextWriterTag.Textarea) { }

        #endregion

        #region [ Public Virtual Properties ]

        /// <summary>
        /// Gets or sets the number of rows in the textarea that gets converted to the editor. This affects the size of the editor.
        /// </summary>
        [Bindable(false), Localizable(false), Category("Behavior"), DefaultValue(-1), Description("The number of rows in the textarea that gets converted to the editor. This affects the size of the editor.")]
        public virtual int Rows
        {
            get { return base.ViewState.GetValue("Rows", -1); }
            set { base.ViewState.SetValue("Rows", value); }
        }

        /// <summary>
        /// Gets or sets the number of columns in the textarea that gets converted to the editor. This affects the size of the editor.
        /// </summary>
        [Bindable(false), Localizable(false), Category("Behavior"), DefaultValue(-1), Description("The number of columns in the textarea that gets converted to the editor. This affects the size of the editor.")]
        public virtual int Columns
        {
            get { return base.ViewState.GetValue("Columns", -1); }
            set { base.ViewState.SetValue("Columns", value); }
        }

        /// <summary>
        /// Gets or sets the name of display mode.
        /// </summary>
        [Bindable(false), Localizable(false), Category("Behavior"), DefaultValue("Simple"), TypeConverter(typeof(DisplayModesConverter)), Description("The name of display mode.")]
        public virtual string DisplayMode
        {
            get { return base.ViewState.GetValue("DisplayMode", "Simple"); }
            set
            {
                Utilities.NotNullOrEmpty(value, "value");
                base.ViewState.SetValue("DisplayMode", value);
            }
        }

        #endregion

        #region [ Protected Virtual Methods ]

        /// <summary>
        /// Raises the TinyMce.TextChanged event.
        /// </summary>
        /// <param name="e">The System.EventArgs object that contains the event data.</param>
        protected virtual void OnTextChanged(EventArgs e)
        {
            EventHandler handler = (EventHandler)base.Events[_textChangedEvent];
            if (handler != null) handler(this, e);
        }

        /// <summary>
        /// Processes postback data for the TinyMce server control.
        /// </summary>
        /// <param name="postDataKey">The key identifier for the control.</param>
        /// <param name="postCollection">The collection of all incoming name values.</param>
        /// <returns>true if the server control's state changes as a result of the postback; otherwise, false.</returns>
        protected virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
        {
            if (postDataKey == this.UniqueID)
            {
                string value = postCollection[postDataKey];
                if (this.Text != value)
                {
                    this.Text = value;
                    return true;
                }
            }
            return false;
        }

        #endregion

        #region [ Overriden Members ]

        /// <summary>
        /// Raises the System.Web.UI.Control.Init event.
        /// </summary>
        /// <param name="e">An System.EventArgs object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            if (!base.DesignMode && this.Page != null)
            {
                // Get current tiny mce editor script manager.
                TinyMceScriptManager scriptManager = TinyMceScriptManager.GetCurrent(this.Page);
                // Throw exception while script manager does not exist.
                Utilities.ThrowOnFailure<HttpException>(scriptManager == null, string.Format(CultureInfo.CurrentCulture, Strings.TinyMceScriptManager_is_required, this.ID));
                // Register tiny mce editor.
                scriptManager.RegisterEditor(this.ClientID, this.DisplayMode);
            }

            base.OnInit(e);
        }

        /// <summary>
        /// Adds HTML attributes and styles that need to be rendered to the specified System.Web.UI.HtmlTextWriterTag. This method is used
        /// primarily by control developers.
        /// </summary>
        /// <param name="writer">
        /// A System.Web.UI.HtmlTextWriter that represents the output stream to render HTML content on the client.</param>
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);

            writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
            if (this.Rows != -1) writer.AddAttribute(HtmlTextWriterAttribute.Rows, this.Rows.ToString(CultureInfo.InvariantCulture));
            if (this.Columns != -1) writer.AddAttribute(HtmlTextWriterAttribute.Cols, this.Columns.ToString(CultureInfo.InvariantCulture));
        }

        /// <summary>
        /// Renders the contents of the control to the specified writer. This method is used primarily by control developers.
        /// </summary>
        /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents the output stream to render HTML content on the client.</param>
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write(this.Text);

            base.RenderContents(writer);
        }

        #endregion

        #region [ IPostBackDataHandler Members ]

        bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
        {
            return this.LoadPostData(postDataKey, postCollection);
        }

        void IPostBackDataHandler.RaisePostDataChangedEvent()
        {
            this.OnTextChanged(EventArgs.Empty);
        }

        #endregion

        #region [ IEditableTextControl Members ]

        [Category("Action")]
        public event EventHandler TextChanged
        {
            add { base.Events.AddHandler(_textChangedEvent, value); }
            remove { base.Events.RemoveHandler(_textChangedEvent, value); }
        }

        #endregion

        #region [ ITextControl Members ]

        /// <summary>
        /// Gets or sets the HTML content of the TinyMce server control.
        /// </summary>
        [Category("Appearance"), DefaultValue(""), PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty), Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
        public virtual string Text
        {
            get { return base.ViewState.GetValue("Text", string.Empty); }
            set { base.ViewState.SetValue("Text", value); }
        }

        #endregion

    }

}
